package open.intellijboy.framework.core.util;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import lombok.extern.slf4j.Slf4j;
import open.intellijboy.framework.core.constant.CommonConstants;
import open.intellijboy.framework.core.exception.ValidationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.regex.Pattern;

/**
 * 参数校验工具类
 *
 * @author System
 * @version 1.0.0
 * @since 2024-01-01
 */
@Slf4j
@Component
public final class ValidatorUtil {

    private static final Pattern PHONE_PATTERN = Pattern.compile(CommonConstants.PHONE_PATTERN);
    private static final Pattern EMAIL_PATTERN = Pattern.compile(CommonConstants.EMAIL_PATTERN);
    private static final Pattern ID_CARD_PATTERN = Pattern.compile(CommonConstants.ID_CARD_PATTERN);

    private static Validator validator;

    @Autowired
    public void setValidator(Validator validator) {
        ValidatorUtil.validator = validator;
    }

    /**
     * 校验对象
     *
     * @param obj 待校验对象
     * @param <T> 对象类型
     * @throws ValidationException 校验失败异常
     */
    public static <T> void validate(T obj) {
        if (obj == null) {
            throw ValidationException.of("校验对象不能为空");
        }

        if (validator == null) {
            log.warn("Validator未初始化，跳过JSR303校验");
            return;
        }

        Set<ConstraintViolation<T>> violations = validator.validate(obj);
        if (!violations.isEmpty()) {
            StringBuilder sb = new StringBuilder();
            for (ConstraintViolation<T> violation : violations) {
                sb.append(violation.getMessage())
                  .append("; ");
            }
            throw ValidationException.of(sb.toString());
        }
    }

    /**
     * 校验对象（指定分组）
     *
     * @param obj    待校验对象
     * @param groups 校验分组
     * @param <T>    对象类型
     * @throws ValidationException 校验失败异常
     */
    public static <T> void validate(T obj, Class<?>... groups) {
        if (obj == null) {
            throw ValidationException.of("校验对象不能为空");
        }

        if (validator == null) {
            log.warn("Validator未初始化，跳过JSR303校验");
            return;
        }

        Set<ConstraintViolation<T>> violations = validator.validate(obj, groups);
        if (!violations.isEmpty()) {
            StringBuilder sb = new StringBuilder();
            for (ConstraintViolation<T> violation : violations) {
                sb.append(violation.getMessage())
                  .append("; ");
            }
            throw ValidationException.of(sb.toString());
        }
    }

    /**
     * 校验手机号
     *
     * @param phone 手机号
     * @return 是否有效
     */
    public static boolean isValidPhone(String phone) {
        if (phone == null || phone.trim()
                                  .isEmpty()) {
            return false;
        }
        return PHONE_PATTERN.matcher(phone)
                            .matches();
    }

    /**
     * 校验邮箱
     *
     * @param email 邮箱
     * @return 是否有效
     */
    public static boolean isValidEmail(String email) {
        if (email == null || email.trim()
                                  .isEmpty()) {
            return false;
        }
        return EMAIL_PATTERN.matcher(email)
                            .matches();
    }

    /**
     * 校验身份证号
     *
     * @param idCard 身份证号
     * @return 是否有效
     */
    public static boolean isValidIdCard(String idCard) {
        if (idCard == null || idCard.trim()
                                    .isEmpty()) {
            return false;
        }
        return ID_CARD_PATTERN.matcher(idCard)
                              .matches();
    }

    /**
     * 校验密码强度
     *
     * @param password 密码
     * @return 是否有效
     */
    public static boolean isValidPassword(String password) {
        if (password == null || password.trim()
                                        .isEmpty()) {
            return false;
        }
        return password.length() >= CommonConstants.PASSWORD_MIN_LENGTH
                && password.length() <= CommonConstants.PASSWORD_MAX_LENGTH;
    }

    /**
     * 校验字符串长度
     *
     * @param str    字符串
     * @param minLen 最小长度
     * @param maxLen 最大长度
     * @return 是否有效
     */
    public static boolean isValidLength(String str, int minLen, int maxLen) {
        if (str == null) {
            return minLen == 0;
        }
        int len = str.length();
        return len >= minLen && len <= maxLen;
    }

    /**
     * 校验数字范围
     *
     * @param num 数字
     * @param min 最小值
     * @param max 最大值
     * @return 是否有效
     */
    public static boolean isValidRange(Number num, Number min, Number max) {
        if (num == null) {
            return false;
        }
        double value = num.doubleValue();
        return value >= min.doubleValue() && value <= max.doubleValue();
    }

    /**
     * 校验非空
     *
     * @param obj 对象
     * @return 是否非空
     */
    public static boolean isNotEmpty(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj instanceof String) {
            return !((String) obj).trim()
                                  .isEmpty();
        }
        if (obj instanceof java.util.Collection) {
            return !((java.util.Collection<?>) obj).isEmpty();
        }
        if (obj instanceof java.util.Map) {
            return !((java.util.Map<?, ?>) obj).isEmpty();
        }
        return true;
    }

    /**
     * 校验手机号并抛出异常
     *
     * @param phone 手机号
     * @throws ValidationException 校验失败异常
     */
    public static void validatePhone(String phone) {
        if (!isValidPhone(phone)) {
            throw ValidationException.of("手机号格式不正确");
        }
    }

    /**
     * 校验邮箱并抛出异常
     *
     * @param email 邮箱
     * @throws ValidationException 校验失败异常
     */
    public static void validateEmail(String email) {
        if (!isValidEmail(email)) {
            throw ValidationException.of("邮箱格式不正确");
        }
    }

    /**
     * 校验身份证号并抛出异常
     *
     * @param idCard 身份证号
     * @throws ValidationException 校验失败异常
     */
    public static void validateIdCard(String idCard) {
        if (!isValidIdCard(idCard)) {
            throw ValidationException.of("身份证号格式不正确");
        }
    }

    /**
     * 校验密码并抛出异常
     *
     * @param password 密码
     * @throws ValidationException 校验失败异常
     */
    public static void validatePassword(String password) {
        if (!isValidPassword(password)) {
            throw ValidationException.of(
                    String.format("密码长度必须在%d-%d位之间",
                            CommonConstants.PASSWORD_MIN_LENGTH,
                            CommonConstants.PASSWORD_MAX_LENGTH));
        }
    }

    /**
     * 校验非空并抛出异常
     *
     * @param obj     对象
     * @param message 错误消息
     * @throws ValidationException 校验失败异常
     */
    public static void validateNotEmpty(Object obj, String message) {
        if (!isNotEmpty(obj)) {
            throw ValidationException.of(message);
        }
    }
}